package com.cmict.data.bpm.service.task;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.cmict.data.bpm.api.instance.dto.BpmProcessInstanceCreateReqDTO;
import com.cmict.data.bpm.api.instance.dto.BpmProcessInstancePageItemRespDTO;
import com.cmict.data.bpm.api.instance.dto.BpmProcessInstancePageReqDTO;
import com.cmict.data.bpm.base.constant.FlowableConstant;
import com.cmict.data.bpm.controller.admin.task.vo.instance.*;
import com.cmict.data.bpm.controller.admin.task.vo.task.BpmTaskApproveReqVO;
import com.cmict.data.bpm.controller.admin.task.vo.task.BpmTaskRespVO;
import com.cmict.data.bpm.convert.task.BpmProcessInstanceConvert;
import com.cmict.data.bpm.dal.dataobject.definition.BpmFormBoundProcessInfo;
import com.cmict.data.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO;
import com.cmict.data.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO;
import com.cmict.data.bpm.dal.dataobject.task.BpmProcessInstanceExtDO;
import com.cmict.data.bpm.dal.mysql.definition.BpmProcessDefinitionExtMapper;
import com.cmict.data.bpm.dal.mysql.task.BpmProcessInstanceExtMapper;
import com.cmict.data.bpm.enums.definition.BpmAutoAgreeEnum;
import com.cmict.data.bpm.enums.definition.BpmTaskAssignRuleTypeEnum;
import com.cmict.data.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum;
import com.cmict.data.bpm.enums.task.BpmProcessInstanceResultEnum;
import com.cmict.data.bpm.enums.task.BpmProcessInstanceStatusEnum;
import com.cmict.data.bpm.framework.bpm.core.event.BpmAllProcessInstanceResultEventPublisher;
import com.cmict.data.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher;
import com.cmict.data.bpm.service.definition.BpmProcessDefinitionService;
import com.cmict.data.bpm.service.definition.BpmTaskAssignRuleService;
import com.cmict.data.bpm.service.message.BpmMessageService;
import com.cmict.data.form.api.task.CurrencyDataApi;
import com.cmict.data.form.api.task.FormDataApi;
import com.cmict.data.form.api.task.dto.SysFormDTO;
import com.cmict.data.framework.common.pojo.CommonResult;
import com.cmict.data.framework.common.pojo.PageResult;
import com.cmict.data.framework.common.util.date.DateUtils;
import com.cmict.data.framework.common.util.number.NumberUtils;
import com.cmict.data.framework.mybatis.core.query.QueryWrapperX;
import com.cmict.data.system.api.dept.DeptApi;
import com.cmict.data.system.api.dept.dto.DeptRespDTO;
import com.cmict.data.system.api.user.AdminUserApi;
import com.cmict.data.system.api.user.dto.AdminUserRespDTO;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.flowable.common.engine.impl.identity.Authentication;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.delegate.event.FlowableCancelledEvent;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.cmict.data.bpm.enums.ErrorCodeConstants.*;
import static com.cmict.data.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.cmict.data.framework.common.pojo.CommonResult.error;
import static com.cmict.data.framework.common.pojo.CommonResult.success;
import static com.cmict.data.framework.common.util.collection.CollectionUtils.convertList;

/**
 * 流程实例 Service 实现类
 *
 * ProcessDefinition & ProcessInstance & Execution & Task 的关系：
 *     1. <a href="https://blog.csdn.net/bobozai86/article/details/105210414" />
 *
 * HistoricProcessInstance & ProcessInstance 的关系：
 *     1. <a href=" https://my.oschina.net/843294669/blog/71902" />
 *
 * 简单来说，前者 = 历史 + 运行中的流程实例，后者仅是运行中的流程实例
 *
 * @author awesome
 */
@Service
@Validated
@Slf4j
public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService {

    @Resource
    private RuntimeService runtimeService;
    @Value("${spring.datasource.dynamic.datasource.slave.name}")
    private String tableSchema;
    @Resource
    private BpmProcessInstanceExtMapper processInstanceExtMapper;
    @Resource
    private BpmProcessDefinitionExtMapper processDefinitionExtMapper;
    @Resource
    @Lazy // 解决循环依赖
    private BpmTaskService taskService;
    @Resource
    private BpmProcessDefinitionService processDefinitionService;
    @Resource
    private HistoryService historyService;
    @Resource
    private AdminUserApi adminUserApi;
    @Resource
    private DeptApi deptApi;
    @Resource
    private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher;
    @Resource
    private BpmAllProcessInstanceResultEventPublisher processAllInstanceResultEventPublisher;
    @Resource
    private BpmMessageService messageService;
    @Resource
    private CurrencyDataApi currencyDataApi;
    @Resource
    private FormDataApi formDataApi;

    @Resource
    private BpmProcessDefinitionService bpmDefinitionService;

    @Resource
    private RepositoryService repositoryService;
    @Resource
    private BpmTaskAssignRuleService taskAssignRuleService;
    @Value("${spring.datasource.dynamic.datasource.slave.name}")
    private String tebleNmae;
    @Value("${callback.url.exchange.offline:}")
    private String OFFLINE_BACK_URL;
    @Override
    public ProcessInstance getProcessInstance(String id) {
        return runtimeService.createProcessInstanceQuery().processInstanceId(id).singleResult();
    }

    @Override
    public List<ProcessInstance> getProcessInstances(Set<String> ids) {
        return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list();
    }

    @Override
    public List<BpmProcessInstanceExtDO> getProcessInstanceExts(Set<String> ids) {
        List<BpmProcessInstanceExtDO> list = new ArrayList<>();
        if(ids!=null && ids.size() > 0){
            for (String id : ids) {
                BpmProcessInstanceExtDO processInstanceExt = processInstanceExtMapper.selectByProcessInstanceId(id);
                if(processInstanceExt !=null){
                    list.add(processInstanceExt);
                }
            }
        }
        return list;
    }

    @Override
    public PageResult<BpmProcessInstancePageItemRespVO> getMyProcessInstancePage(Long userId,
                                                                                 BpmProcessInstanceMyPageReqVO pageReqVO) {
        String formStatusAndResult = pageReqVO.getFormStatusAndResult();
        List<String> formStatusAndResultList = StringUtils.isNoneBlank(formStatusAndResult) &&  formStatusAndResult.contains("-") ? Arrays.asList(formStatusAndResult.split("-")) : new ArrayList<>();
        if (formStatusAndResultList.size() > 0) {
            int formStatus = Integer.valueOf(formStatusAndResultList.get(0));
            int result = Integer.valueOf(formStatusAndResultList.get(1));
            pageReqVO.setFormStatus(formStatus).setResult(result);
        }
        // 通过 BpmProcessInstanceExtDO 表，先查询到对应的分页
//        PageResult<BpmProcessInstanceExtDO> pageResulttemp = processInstanceExtMapper.selectPage(userId, pageReqVO);

        Long size = processInstanceExtMapper.selectPageProcessInstanceCount(userId,pageReqVO);
        pageReqVO.setPageNo(pageReqVO.getPageSize()*(pageReqVO.getPageNo()-1));
        List<BpmProcessInstancePageItemRespVO> list = processInstanceExtMapper.selectPageProcessInstance(userId,pageReqVO);
        if (list.size()==0) {
            return new PageResult<>(0L);
        }
        // 获得流程 Task Map
        List<String> processInstanceIds = convertList(list, BpmProcessInstancePageItemRespVO::getId);
        Map<String, List<Task>> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds);
        //List<BpmProcessInstancePageItemRespVO> listclean = new ArrayList<>();
        list.forEach(respVO -> {
           /* if(ObjectUtil.isNotEmpty(respVO.getFormRecordId()) && ObjectUtil.isNotEmpty(respVO.getFormJsonData())){
                listclean.add(respVO);
            }*/
            respVO.setTasks(BpmProcessInstanceConvert.INSTANCE.convertList2(taskMap.get(respVO.getId())));
        });
        PageResult<BpmProcessInstancePageItemRespVO> result = new PageResult<>(list,size);
        return result;
    }

    @Override
    public List<BpmProcessInstancePageItemRespVO> getMyProcessInstanceNoPage(Long userId, BpmProcessInstanceMyReqVO reqVO) {
        String formStatusAndResult = reqVO.getFormStatusAndResult();
        List<String> formStatusAndResultList = StringUtils.isNoneBlank(formStatusAndResult) &&  formStatusAndResult.contains("-") ? Arrays.asList(formStatusAndResult.split("-")) : new ArrayList<>();
        if (formStatusAndResultList.size() > 0) {
            int formStatus = Integer.valueOf(formStatusAndResultList.get(0));
            int result = Integer.valueOf(formStatusAndResultList.get(1));
            reqVO.setFormStatus(formStatus).setResult(result);
        }
        List<BpmProcessInstancePageItemRespVO> list = processInstanceExtMapper.selectProcessInstanceNoPage(userId,reqVO);

        // 获得流程 Task Map
        List<String> processInstanceIds = convertList(list, BpmProcessInstancePageItemRespVO::getId);
        Map<String, List<Task>> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds);

        list.forEach(respVO -> {
            respVO.setTasks(BpmProcessInstanceConvert.INSTANCE.convertList2(taskMap.get(respVO.getId())));
        });
        return list;
    }

    @Override
    public PageResult<BpmProcessInstancePageItemRespDTO> getProcessInstancePage(Long userId, BpmProcessInstancePageReqDTO pageReqVO) {
        BpmProcessInstanceMyPageReqVO processInstanceMyPageReqVO = BpmProcessInstanceConvert.INSTANCE.convert(pageReqVO);
        PageResult<BpmProcessInstanceExtDO> pageResult = processInstanceExtMapper.selectPage(userId, processInstanceMyPageReqVO);
        if (CollUtil.isEmpty(pageResult.getList())) {
            return new PageResult<>(pageResult.getTotal());
        }
        List<String> processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId);
        Map<String, List<Task>> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds);
        // 转换返回

        return BpmProcessInstanceConvert.INSTANCE.convertPage1(pageResult, taskMap);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) {
        Map<String, Object> variables = createReqVO.getVariables();
        SysFormDTO sysForm = formDataApi.getSysFormById(createReqVO.getFormId());
        String sql = "SELECT  * from " + tableSchema +"." + sysForm.getTableName() + " WHERE 1 = 1 and id  =  " + createReqVO.getFormRecordId();
        Map<String,Object> data =   processInstanceExtMapper.getSysFormDataById(sql);
         if(null != data && !data.isEmpty()){
             Set<String> keySet = data.keySet();
             for (String key : keySet) {
                 if(variables.containsKey(key)){
                     variables.put(key,data.get(key));
                 }
             }
         }
        if(createReqVO.getFormId()!=null && !isBoundFormAndProcess(createReqVO.getFormId())){
            throw exception(FORM_PROCESS_IS_NOT_BOUND);
        }
        // 根据表单id和记录id判断流程是否已发起流程
//        if(createReqVO.getFormId()!=null && createReqVO.getFormRecordId()!=null && checkFormRecordIdIsExit(createReqVO.getFormId(),createReqVO.getFormRecordId())){
//            throw exception(FORM_RECORD_PROCESS_INSTANCE_EXISTS);
//        }
        // 根据表单id获取流程定义id
        if(StrUtil.isBlank(createReqVO.getProcessDefinitionId())){
            createReqVO.setProcessDefinitionId(processDefinitionExtMapper.selectByFormId(createReqVO.getFormId()).getProcessDefinitionId());
        }
        // 获得流程定义
        ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId());
        // 发起流程
        return createProcessInstance0(userId, definition,createReqVO.getFormRecordId(),createReqVO.getVariables(), null,createReqVO.getFormStatus());
//        return createProcessInstance0(userId, definition, createReqVO.getVariables(), null);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String batchCreateProcessInstance(Long userId,  List<BpmProcessInstanceCreateReqVO> createReqVOList) {
        for (BpmProcessInstanceCreateReqVO createReqVO : createReqVOList) {
            if(createReqVO.getFormId()!=null && !isBoundFormAndProcess(createReqVO.getFormId())){
                throw exception(FORM_PROCESS_IS_NOT_BOUND);
            }
            // 根据表单id和记录id判断流程是否已发起流程
            BpmProcessInstanceStatusReqVo processInstance = getProcessInstanceStatus(createReqVO.getFormId(), Long.valueOf(createReqVO.getFormRecordId()));
            if( processInstance.getResult() != null && processInstance.getResult()!=5 && processInstance.getResult()!=4 ) {
                throw exception(FORM_RECORD_PROCESS_INSTANCE_EXISTS);
            }
            // 根据表单id获取流程定义id
            if(StrUtil.isBlank(createReqVO.getProcessDefinitionId())){
                createReqVO.setProcessDefinitionId(processDefinitionExtMapper.selectByFormId(createReqVO.getFormId()).getProcessDefinitionId());
            }
            // 获得流程定义
            ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId());
            // 发起流程
             createProcessInstance0(userId, definition,createReqVO.getFormRecordId(),createReqVO.getVariables(), null,createReqVO.getFormStatus());
//        return createProcessInstance0(userId, definition, createReqVO.getVariables(), null);
        }
        return null;
    }

    @Override
    public String createProcessInstance(Long userId, BpmProcessInstanceCreateReqDTO createReqDTO) {
        // 获得流程定义
        ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey());
        // 发起流程
        return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey());
    }

    @Override
    public BpmProcessInstanceRespVO getProcessInstanceVO(String id) {
        // 获得流程实例
        HistoricProcessInstance processInstance = getHistoricProcessInstance(id);
        if (processInstance == null) {
            return null;
        }
        BpmProcessInstanceExtDO processInstanceExt = processInstanceExtMapper.selectByProcessInstanceId(id);
        Assert.notNull(processInstanceExt, "流程实例拓展({}) 不存在", id);

        // 获得流程定义
        ProcessDefinition processDefinition = processDefinitionService
                .getProcessDefinition(processInstance.getProcessDefinitionId());
        Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId());
        BpmProcessDefinitionExtDO processDefinitionExt = processDefinitionService.getProcessDefinitionExt(
                processInstance.getProcessDefinitionId());
        Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id);
        String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId());

        // 获得 User
        CommonResult<AdminUserRespDTO> result = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId()));
        AdminUserRespDTO startUser = result.getCheckedData();
        DeptRespDTO dept = null;
        if (startUser != null) {
            CommonResult<DeptRespDTO> deptResult = deptApi.getDept(startUser.getDeptId());
            dept = deptResult.getCheckedData();
        }
        //远端数据映射
        LocalDateTime createTime = processInstanceExt.getCreateTime();
        LocalDateTime oldDataTime = LocalDateTime.of(2023, 1, 16, 15, 0);
        if (createTime.isAfter(oldDataTime)) {
            formDataMap(processDefinitionExt.getFormId(), processInstanceExt);
        }
        // 拼接结果
        return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processInstanceExt,
                processDefinition, processDefinitionExt, bpmnXml, startUser, dept);
    }

    @Override
    public BpmProcessInstanceRespVO getBatchApprovalDetail(List<String> ids) {
        List<Map<String,Object>> formVariablesList = new ArrayList<>();
        List<List<String>> formFieldsList = new ArrayList<>();
        List<String> idList = new ArrayList<>();
        Long formId = 0L;
        for (String id : ids) {
            // 获得流程实例
            HistoricProcessInstance processInstance = getHistoricProcessInstance(id);
            if (processInstance == null) {
                return null;
            }
            BpmProcessInstanceExtDO processInstanceExt = processInstanceExtMapper.selectByProcessInstanceId(id);
            Assert.notNull(processInstanceExt, "流程实例拓展({}) 不存在", id);
            // 获得流程定义
            ProcessDefinition processDefinition = processDefinitionService
                    .getProcessDefinition(processInstance.getProcessDefinitionId());
            Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId());
            BpmProcessDefinitionExtDO processDefinitionExt = processDefinitionService.getProcessDefinitionExt(
                    processInstance.getProcessDefinitionId());
            Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id);
            String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId());

            // 获得 User
            CommonResult<AdminUserRespDTO> result = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId()));
            AdminUserRespDTO startUser = result.getCheckedData();
            DeptRespDTO dept = null;
            if (startUser != null) {
                CommonResult<DeptRespDTO> deptResult = deptApi.getDept(startUser.getDeptId());
                dept = deptResult.getCheckedData();
            }
            formFieldsList.add(processDefinitionExt.getFormFields());
            //远端数据映射
            LocalDateTime createTime = processInstanceExt.getCreateTime();
            LocalDateTime oldDataTime = LocalDateTime.of(2023, 1, 16, 15, 0);
            if (createTime.isAfter(oldDataTime)) {
                formDataMap(processDefinitionExt.getFormId(), processInstanceExt);
            }
            formId = processDefinitionExt.getFormId();
            formVariablesList.add(processInstanceExt.getFormVariables());
            BpmTaskRespVO bpmTaskRespVO = taskService.getTaskListByProcessInstanceId(id).get(0);
            idList.add(bpmTaskRespVO.getId());
        }

        String id = ids.get(0);
        // 获得流程实例
        HistoricProcessInstance processInstance = getHistoricProcessInstance(id);
        if (processInstance == null) {
            return null;
        }
        BpmProcessInstanceExtDO processInstanceExt = processInstanceExtMapper.selectByProcessInstanceId(id);
        //远端数据映射
        LocalDateTime createTime = processInstanceExt.getCreateTime();
        LocalDateTime oldDataTime = LocalDateTime.of(2023, 1, 16, 15, 0);
        if (createTime.isAfter(oldDataTime)) {
            formDataMap(formId, processInstanceExt);
        }
        processInstanceExt.setFormVariablesList(formVariablesList);
        processInstanceExt.setIdList(idList);
        Assert.notNull(processInstanceExt, "流程实例拓展({}) 不存在", id);

        // 获得流程定义
        ProcessDefinition processDefinition = processDefinitionService
                .getProcessDefinition(processInstance.getProcessDefinitionId());
        Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId());
        BpmProcessDefinitionExtDO processDefinitionExt = processDefinitionService.getProcessDefinitionExt(
                processInstance.getProcessDefinitionId());
        Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id);
        processDefinitionExt.setFormFieldsList(formFieldsList);
        String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId());

        // 获得 User
        CommonResult<AdminUserRespDTO> result = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId()));
        AdminUserRespDTO startUser = result.getCheckedData();
        DeptRespDTO dept = null;
        if (startUser != null) {
            CommonResult<DeptRespDTO> deptResult = deptApi.getDept(startUser.getDeptId());
            dept = deptResult.getCheckedData();
        }
        //获得附件
        // 拼接结果
        return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processInstanceExt,
                processDefinition, processDefinitionExt, bpmnXml, startUser, dept);
    }

    @Override
    public List<BpmProcessInstanceExtDO> getProcessInstanceData(String id, String processId) {
        List<BpmProcessInstanceExtDO> dataList = processInstanceExtMapper.selectByProcessDefinitionIdData(id,processId);
        return dataList;
    }

    @Override
    public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) {
        // 校验流程实例存在
        ProcessInstance instance = getProcessInstance(cancelReqVO.getId());
        if (instance == null) {
            throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS);
        }
        // 只能取消自己的
        if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) {
            throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF);
        }

        // 通过删除流程实例，实现流程实例的取消,
        // 删除流程实例，正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询
        String reason = BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format(cancelReqVO.getReason());
        deleteProcessInstance(cancelReqVO.getId(), reason);
        taskService.cancelTask(cancelReqVO.getId());
    }

    @Override
    public Boolean updateFormVariables(String bpmInstanceId,Long newMenuId,Long newDeptId) {
        try{
            BpmProcessInstanceExtDO processInstanceExt = processInstanceExtMapper.selectByProcessInstanceId(bpmInstanceId);
            if (processInstanceExt != null) {
                Map<String, Object>  formVariablesMap = processInstanceExt.getFormVariables();
                formVariablesMap.put("menu_id", newMenuId);
                formVariablesMap.put("dept_id", newDeptId);
                BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO()
                        .setProcessInstanceId(bpmInstanceId)
                        .setFormVariables(formVariablesMap);
                processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO);
            }
        }catch (Exception e){
            return false;
        }
        return true;
    }

    /**
     * 获得历史的流程实例
     *
     * @param id 流程实例的编号
     * @return 历史的流程实例
     */
    @Override
    public HistoricProcessInstance getHistoricProcessInstance(String id) {
        return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult();
    }

    @Override
    public List<HistoricProcessInstance> getHistoricProcessInstances(Set<String> ids) {
        return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list();
    }

    @Override
    public void createProcessInstanceExt(ProcessInstance instance) {
        // 获得流程定义
        ProcessDefinition definition = processDefinitionService.getProcessDefinition2(instance.getProcessDefinitionId());
        // 插入 BpmProcessInstanceExtDO 对象
        BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO()
                .setProcessInstanceId(instance.getId())
                .setProcessDefinitionId(definition.getId())
                .setName(instance.getProcessDefinitionName())
                .setStartUserId(Long.valueOf(instance.getStartUserId()))
                .setCategory(definition.getCategory())
                .setStatus(BpmProcessInstanceStatusEnum.RUNNING.getStatus())
                .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult());

        processInstanceExtMapper.insert(instanceExtDO);
    }

    @Override
    public void updateProcessInstanceExtCancel(FlowableCancelledEvent event) {
        // 判断是否为 Reject 不通过。如果是，则不进行更新.
        // 因为，updateProcessInstanceExtReject 方法，已经进行更新了
        if (BpmProcessInstanceDeleteReasonEnum.isRejectReason((String)event.getCause())) {
            return;
        }

        // 需要主动查询，因为 instance 只有 id 属性
        // 另外，此时如果去查询 ProcessInstance 的话，字段是不全的，所以去查询了 HistoricProcessInstance
        HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId());
        // 更新拓展表
        BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO()
                .setProcessInstanceId(event.getProcessInstanceId())
                .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime，所以这里设置
                .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus())
                .setResult(BpmProcessInstanceResultEnum.CANCEL.getResult());

        processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO);

        // 发送流程实例的状态事件
        processInstanceResultEventPublisher.sendProcessInstanceResultEvent(
                BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult()));
        processAllInstanceResultEventPublisher.sendAllProcessInstanceResultEvent(
                BpmProcessInstanceConvert.INSTANCE.convertAll(this, processInstance, instanceExtDO.getResult()));
    }

    @Override
    public void updateProcessInstanceExtComplete(ProcessInstance instance) {
        // 需要主动查询，因为 instance 只有 id 属性
        // 另外，此时如果去查询 ProcessInstance 的话，字段是不全的，所以去查询了 HistoricProcessInstance
        HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId());
        // 更新拓展表
        BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO()
                .setProcessInstanceId(instance.getProcessInstanceId())
                .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime，所以这里设置
                .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus())
                .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()); // 如果正常完全，说明审批通过
        processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO);

        // 发送流程被通过的消息
//        messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance));
        BpmProcessInstanceExtDO bpmProcessInstance = processInstanceExtMapper.selectByProcessInstanceId(instance.getId());
        if(null != bpmProcessInstance && 3 == bpmProcessInstance.getFormStatus()){
            BpmProcessDefinitionExtDO bpmProcessDefinition = processDefinitionExtMapper.selectByProcessDefinitionId(processInstance.getProcessDefinitionId());
            if(null != bpmProcessDefinition && null != bpmProcessDefinition.getFormId()){
                CommonResult result = formDataApi.getDataByIds(bpmProcessInstance.getFormRecordId(),bpmProcessDefinition.getFormId());
                Map entity = (Map)result.getCheckedData();
                if(entity.containsKey("data_id") && null != entity.get("data_id")){
                    RestTemplate restTemplateOffline = new RestTemplate();
                    Long resourceId = ((Integer) entity.get("data_id")).longValue();
                    Map<String, Object> formVariables = new HashMap<>();
                    formVariables.put("resourceId",resourceId);
                    restTemplateOffline.postForEntity(OFFLINE_BACK_URL,formVariables,String.class);
                }
            }
        }

        // 发送流程实例的状态事件
        processInstanceResultEventPublisher.sendProcessInstanceResultEvent(
                BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult()));
        processAllInstanceResultEventPublisher.sendAllProcessInstanceResultEvent(
                BpmProcessInstanceConvert.INSTANCE.convertAll(this, processInstance, instanceExtDO.getResult()));
    }

    @Transactional(rollbackFor = Exception.class)
    public void updateProcessInstanceExtReject(String id, String reason) {
        // 需要主动查询，因为 instance 只有 id 属性
        ProcessInstance processInstance = getProcessInstance(id);
        // 删除流程实例，以实现驳回任务时，取消整个审批流程
        deleteProcessInstance(id, StrUtil.format(BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.format(reason)));

        // 更新 status + result
        // 注意，不能和上面的逻辑更换位置。因为 deleteProcessInstance 会触发流程的取消，进而调用 updateProcessInstanceExtCancel 方法，
        // 设置 result 为 BpmProcessInstanceStatusEnum.CANCEL，显然和 result 不一定是一致的
        BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO().setProcessInstanceId(id)
                .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus())
                .setResult(BpmProcessInstanceResultEnum.REJECT.getResult())
                .setEndTime(LocalDateTime.now());
        processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO);

        // 发送流程被不通过的消息
        messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason));

        // 发送流程实例的状态事件
        processInstanceResultEventPublisher.sendProcessInstanceResultEvent(
                BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult()));
        processAllInstanceResultEventPublisher.sendAllProcessInstanceResultEvent(
                BpmProcessInstanceConvert.INSTANCE.convertAll(this, processInstance, instanceExtDO.getResult()));
    }

    private void deleteProcessInstance(String id, String reason) {
        runtimeService.deleteProcessInstance(id, reason);
    }

    private String createProcessInstance0(Long userId, ProcessDefinition definition,
                                          Map<String, Object> variables, String businessKey) {
        // 校验流程定义
        if (definition == null) {
            throw exception(PROCESS_DEFINITION_NOT_EXISTS);
        }
        if (definition.isSuspended()) {
            throw exception(PROCESS_DEFINITION_IS_SUSPENDED);
        }

        // 创建流程实例
        ProcessInstance instance = runtimeService.startProcessInstanceById(definition.getId(), businessKey, variables);
        // 设置流程名字
        runtimeService.setProcessInstanceName(instance.getId(), definition.getName());

        // 补全流程实例的拓展表
        processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId())
                .setFormVariables(variables));
        // 如果用户为实例发起人，自动完成任务
        this.autoCommitSubmitterTask(userId, instance.getId());
        return instance.getId();
    }

    public BpmProcessInstanceStatusReqVo getProcessInstanceStatus(Long formId,Long formRecordId) {
        // 1、根据表单id获取其关联的流程最新的模型id对应的流程定义ids
        List<String> processDefineIds = new ArrayList<>(processDefinitionExtMapper.getDefineIdsByFormId(formId));
        // 2、在流程定义ids中的流程实例对应的最新表单记录id、result
        BpmProcessInstanceExtDO bpmProcessInstanceExtDO = processInstanceExtMapper.selectOne(
                new QueryWrapperX<BpmProcessInstanceExtDO>().lambda().in(BpmProcessInstanceExtDO::getFormRecordId,formRecordId)
                        .in(BpmProcessInstanceExtDO::getProcessDefinitionId,processDefineIds)
                        .orderByDesc(BpmProcessInstanceExtDO::getCreateTime)
                        .last("limit 1"));
        BpmProcessInstanceStatusReqVo bpmProcessInstanceStatusReqVo = new BpmProcessInstanceStatusReqVo();
        BeanUtil.copyProperties(bpmProcessInstanceExtDO,bpmProcessInstanceStatusReqVo);
        return bpmProcessInstanceStatusReqVo;
    }
//    @Override
//    public CommonResult getFormDataAndStatus(Long loginUserId, SysFromSeachDataVoDTO sysFromSeachData) {
//        String sql = "select table_name from information_schema.tables where table_schema='"+tebleNmae+"';";
//        List<String> tableNameLIst = currencyDataApi.getTableNameList(sql).getCheckedData();
//        Long formId = null;
//        if(StringUtils.isNotEmpty(sysFromSeachData.getTableName())){
//            SqlParameterCheck.checkMatch(sysFromSeachData.getTableName());
//        }
//        if(tableNameLIst.contains(sysFromSeachData.getTableName())){
//            // 根据表名获取表单id
//            try {
//                formId = formDataApi.getFormIdByTableName(sysFromSeachData.getTableName());
//            }catch (Exception e){
//                return error(500,"数据库已经不存在，请重新创建");
//            }
//            CommonResult result= currencyDataApi.selectData(sysFromSeachData);
//            if(!isBoundFormAndProcess(formId)){
//                String groupField = sysFromSeachData.getGroupField();
//                if(StringUtils.isNoneBlank(groupField)){
//                    return  groupByCode(result,groupField);
//                }
//                return result;
//            }
//            JSONObject data = (JSONObject) JSON.toJSON(result.getData());
//            if(data.get("size") == null){
//                ArrayList arrayList = (ArrayList) data.get("records");
//                for (Object o : arrayList) {
//                    Map record = (Map) o;
//                    BpmProcessInstanceStatusReqVo bpmProcessInstanceStatusReqVo = getProcessInstanceStatus(formId, Long.getLong(record.get("id").toString()));
//                    if (bpmProcessInstanceStatusReqVo != null) {
//                        record.put("result", bpmProcessInstanceStatusReqVo.getResult() == null ? 4 : bpmProcessInstanceStatusReqVo.getResult());
//                        record.put("processInstanceId", bpmProcessInstanceStatusReqVo.getProcessInstanceId());
//                        record.put("formStatus", bpmProcessInstanceStatusReqVo.getFormStatus());
//                        record.put("processDefinitionId", bpmProcessInstanceStatusReqVo.getProcessDefinitionId());
//                    }
//                }
//                result.setData(arrayList);
//                String groupField = sysFromSeachData.getGroupField();
//                if(StringUtils.isNoneBlank(groupField)){
//                    return    groupByCode(result,groupField);
//                }
//            }else{
//                JSONArray records = data.getJSONArray("records");
//                for (Object o : records) {
//                    JSONObject record = (JSONObject) o;
//                    BpmProcessInstanceStatusReqVo bpmProcessInstanceStatusReqVo = getProcessInstanceStatus(formId, record.getLong("id"));
//                    if (bpmProcessInstanceStatusReqVo != null) {
//                        record.put("result", bpmProcessInstanceStatusReqVo.getResult() == null ? 4 : bpmProcessInstanceStatusReqVo.getResult());
//                        record.put("processInstanceId", bpmProcessInstanceStatusReqVo.getProcessInstanceId());
//                        record.put("formStatus", bpmProcessInstanceStatusReqVo.getFormStatus());
//                        record.put("processDefinitionId", bpmProcessInstanceStatusReqVo.getProcessDefinitionId());
//                    }
//                }
//                result.setData(data);
//                String groupField = sysFromSeachData.getGroupField();
//                if(StringUtils.isNoneBlank(groupField)){
//                    return    groupByCode(result,groupField);
//                }
//            }
//            return result;
//
//        }
//        return success("数据库表名不存在！",null);
//
//    }

//    /**
//     * 分组算法
//     * @param result
//     * @param groupField
//     * @return
//     */
//    private CommonResult groupByCode(CommonResult result, String groupField) {
//        JSONObject data = (JSONObject) JSON.toJSON(result.getData());
//        JSONArray records = data.getJSONArray("records");
//        Map<String, List<Object>> dataMap = new TreeMap<>();
//        List<Object> list = new ArrayList<>();
//        //数据分组算法
//        for (Object o : records) {
//            JSONObject json = JSONObject.parseObject(o.toString());
//            List<Object> tempList = (List<Object>) dataMap.get(json.get(groupField) !=null ? json.get(groupField).toString() : json.get(groupField));
//            if(tempList == null) { //说明是第一次，则创建list
//                tempList = new ArrayList<>();
//                tempList.add(json);
//                dataMap.put(json.get(groupField).toString(), tempList);//放入map中
//            }else {
//                tempList.add(json);
//            }
//        }
//        //遍历
//        int i =1;
//        for (String group : dataMap.keySet()) {
//            i++;
//            Map<String, Object> map = new HashMap<>();
//            map.put("groupField",group);
//            map.put("id","a"+ i);
//            map.put("parentId",0);
//            List<Object> datalist = dataMap.get(group);
//            List<Object> resultList = new ArrayList<>();
//            if(datalist!=null && datalist.size() >0 ){
//                for (Object o : datalist) {
//                    JSONObject json = JSONObject.parseObject(o.toString());
//                    json.put("parentId","a"+ i);
//                    resultList.add(json);
//                }
//            }
//            map.put("children",resultList);
//            list.add(map);
//        }
//        data.put("records",list);
//        result.setData(data);
//        return result;
//    }

    @Override
    public Boolean isBoundFormAndProcess(Long formId) {
        BpmProcessDefinitionExtDO processDefinitionExtDO = processDefinitionExtMapper.selectByFormId(formId);
        String processDefineId = processDefinitionExtDO ==null ? null:processDefinitionExtDO.getProcessDefinitionId();
        if(processDefineId==null){
            return false;
        }
        ProcessDefinition definition = processDefinitionService.getProcessDefinition(processDefineId);
        // 校验流程定义
        if (definition == null || definition.isSuspended()) {
            return false;
        }
        return true;
    }

    @Override
    public void updateProcessInstanceExtBack(String id, String comment) {
        // 需要主动查询，因为 instance 只有 id 属性
        ProcessInstance processInstance = getProcessInstance(id);
        // 删除流程实例，以实现驳回任务时，取消整个审批流程
        deleteProcessInstance(id, StrUtil.format(BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.format(comment)));

        // 更新 status + result
        // 注意，不能和上面的逻辑更换位置。因为 deleteProcessInstance 会触发流程的取消，进而调用 updateProcessInstanceExtCancel 方法，
        // 设置 result 为 BpmProcessInstanceStatusEnum.CANCEL，显然和 result 不一定是一致的
        BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO().setProcessInstanceId(id)
                .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus())
                .setResult(BpmProcessInstanceResultEnum.BACK.getResult());
        processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO);

        // 发送流程被驳回的消息(TODO)
        //messageService.sendMessageWhenProcessInstanceBack(BpmProcessInstanceConvert.INSTANCE.convert2BackReq(processInstance, comment));

        // 发送流程实例的状态事件
        processInstanceResultEventPublisher.sendProcessInstanceResultEvent(
                BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult()));
        processAllInstanceResultEventPublisher.sendAllProcessInstanceResultEvent(
                BpmProcessInstanceConvert.INSTANCE.convertAll(this, processInstance, instanceExtDO.getResult()));
    }

    @Override
    public void deleteProcessInstances(Long userId, BpmProcessInstanceDeleteReqVO deleteReqVO) {
        List<String> instanceIds = deleteReqVO.getInstanceIds();
        if(instanceIds.size()>0){
            instanceIds.forEach(instanceId ->{
                if(instanceId!=null){
                    ProcessInstance instance = getProcessInstance(instanceId);
                    if (instance != null) {
                        // 通过删除流程实例，实现流程实例的取消,
                        // 删除流程实例，正则执行任务ACT_RU_TASK. 任务会被删除。通过历史表查询
                        deleteProcessInstance(instanceId, BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format("删除"));
                    }
                    //删除实例扩展表中的实例
                    processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instanceId).setDeleted(true));
                }
            });
        }
    }

    @Override
    public PageResult<BpmProcessInstanceDraftPageResVO> getMyFormProcessDraftPage(Long loginUserId,BpmProcessInstanceDraftReqVO draftReqVO) {
        // 1、根据当前用户角色id获取当前用户的菜单id
        //Set<Long> menuIds =  permissionService.getUserMenuIds(loginUserId);
        // 2、根据菜单id获取当前用户的表单信息
        Set<Long> userMenuIds = formDataApi.getUserMenuId();
        Set<Long> loginUserFormMenuIds = new HashSet<>(userMenuIds);
        //loginUserFormMenuIds.retainAll(menuIds);
        String formMenuIds ="'"+ StringUtils.join(loginUserFormMenuIds,"','")+"'";
        List<SysFormDTO> sysForms = formDataApi.getSysFormByUseMenuIds(formMenuIds);
        // 3、分别查询不同form的用户页面当前用户提交的未发起审批的数据：表单记录id、表单变量、创建时间、表单jsondata
        List<BpmProcessInstanceDraftPageResVO> draftResVOS = new ArrayList<>();
        sysForms.forEach(sysForm -> {
            Long formId = sysForm.getId();
            BpmFormBoundProcessInfo formBoundProcessInfo = getFormBoundProcessInfo(formId);
            Boolean isBound = formBoundProcessInfo.getIsBound();
            String modelName = formBoundProcessInfo.getModelName();
            String tableName = sysForm.getTableName();
            //确定用户提交类型字段名和用户id字段名
            String sql = "select id,create_time from " + tableName + " where data_type = 1 and creator =" + loginUserId;
            List<Map<String,Object>> formDatas = currencyDataApi.selectDataList(sql);
            for (int i = 0; i < formDatas.size();i ++) {
                BpmProcessInstanceDraftPageResVO draftPageResVO = new BpmProcessInstanceDraftPageResVO();
                Long formRecordId = (Long) formDatas.get(i).get("id");
                LocalDateTime createTime = DateUtils.of((Date) formDatas.get(i).get("create_time"));
                if (!isBound) {
                    draftPageResVO.setFormId(formId).setFormRecordId(formRecordId).setCreateTime(createTime)
                            .setFormName(sysForm.getFormName()).setFormJsonData(sysForm.getFormJsonData())
                            .setFormJsonUser(sysForm.getFormJsonUser());
                    draftResVOS.add(draftPageResVO);
                } else {
                    Integer processInstanceResult = getProcessInstanceStatus(formId,formRecordId).getResult();
                    if (processInstanceResult ==null || (processInstanceResult!=null && processInstanceResult.equals(BpmProcessInstanceResultEnum.CANCEL.getResult()))) {
                        draftPageResVO.setFormId(formId).setFormRecordId(formRecordId).setCreateTime(createTime).setFormJsonUser(sysForm.getFormJsonUser())
                                .setFormName(sysForm.getFormName()).setFormJsonData(sysForm.getFormJsonData()).setProcessModelName(modelName);
                        draftResVOS.add(draftPageResVO);
                    }
                }
            }
        });
        Long total = Long.valueOf(draftResVOS.size());
        List<BpmProcessInstanceDraftPageResVO>  draftPageResVOS = new ArrayList<>();
        // 4、所有表单数据按照创建时间排序并分页
        if(StrUtil.isNotBlank(draftReqVO.getFormName())){
            draftPageResVOS =  draftResVOS.stream().filter(draftResVO->draftReqVO.getFormName().equals(draftResVO.getFormName())).sorted(Comparator.comparing(BpmProcessInstanceDraftPageResVO::getCreateTime).reversed())
                    .skip((draftReqVO.getPageNo()-1) * draftReqVO.getPageSize()).limit(draftReqVO.getPageSize())
                    .collect(Collectors.toList());
        }else {
            draftPageResVOS =  draftResVOS.stream().sorted(Comparator.comparing(BpmProcessInstanceDraftPageResVO::getCreateTime).reversed())
                    .skip((draftReqVO.getPageNo()-1) * draftReqVO.getPageSize()).limit(draftReqVO.getPageSize())
                    .collect(Collectors.toList());
        }

        PageResult pageResult = new PageResult(draftPageResVOS, total);

        return pageResult;
    }

    @Override
    @Transactional
    public Boolean deleteMyDraft(List<BpmProcessInstanceDraftDeleteReqVO> draftDeleteReqVOs) {
        draftDeleteReqVOs.forEach(draftDeleteReqVO -> {
            String sql = "DELETE FROM " + tebleNmae+"."+draftDeleteReqVO.getTableName() + " where id = "+ draftDeleteReqVO.getId();
            currencyDataApi.deleteData(sql);
        });
        return true;
    }

    @Override
    public Set<Integer> getProcessInstancesByDefinition(Set<String> processDefinitionId) {
        List<BpmProcessInstanceExtDO> instanceExtDOS = processInstanceExtMapper.selectByProcessDefinitionId(processDefinitionId);
        if (Objects.isNull(instanceExtDOS)) {
            throw exception(PROCESS_INSTANCE_NOT_EXISTS);
        }
        Set<Integer> formRecordIdSet = new HashSet<>();
        Set<Integer> formRecordSet = new HashSet<>();
        instanceExtDOS.forEach(item -> {
            if (!formRecordIdSet.contains(item.getFormRecordId())) {
                formRecordIdSet.add(item.getFormRecordId());
               if (item.getResult().equals(BpmProcessInstanceResultEnum.APPROVE.getResult())){
                   formRecordSet.add(item.getFormRecordId());
               }
            }
        });
        return formRecordSet;
    }


    private BpmFormBoundProcessInfo getFormBoundProcessInfo(Long formId) {
        BpmFormBoundProcessInfo formBoundProcessInfo = new BpmFormBoundProcessInfo();
        BpmProcessDefinitionExtDO processDefinitionExtDO = processDefinitionExtMapper.selectByFormId(formId);
        String processDefineId = processDefinitionExtDO==null? null:processDefinitionExtDO.getProcessDefinitionId();
        if(processDefineId==null){
            formBoundProcessInfo.setIsBound(false);
            return formBoundProcessInfo;
        }

        ProcessDefinition definition = processDefinitionService.getProcessDefinition(processDefineId);
        // 校验流程定义
        if (definition == null || definition.isSuspended()) {
            formBoundProcessInfo.setIsBound(false);
            return formBoundProcessInfo;
        }else {
            formBoundProcessInfo.setIsBound(true);
            String modelId =  processDefinitionExtDO.getModelId();
            String modelName = repositoryService.createModelQuery().modelId(modelId).list().get(0).getName();
            formBoundProcessInfo.setModelName(modelName);
        }

        return formBoundProcessInfo;
    }

    private String createProcessInstance0(Long userId, ProcessDefinition definition,Integer formRecordId,
                                          Map<String, Object> variables, String businessKey,Integer formStatus) {
        // 校验流程定义
        if (definition == null) {
            throw exception(PROCESS_DEFINITION_NOT_EXISTS);
        }

        if (definition.isSuspended()) {
            throw exception(PROCESS_DEFINITION_IS_SUSPENDED);
        }
        if (variables != null && !variables.isEmpty()) {
            // 默认设置流程启动人变量 initiator
            variables.put(FlowableConstant.FLOW_SUBMITTER_VAR, userId);
        } else {
            variables = new HashMap<>(1);
            // 默认设置流程启动人变量 initiator
            variables.put(FlowableConstant.FLOW_SUBMITTER_VAR, userId);
        }
        Authentication.setAuthenticatedUserId(String.valueOf(userId));
        // 创建流程实例
        ProcessInstance instance = runtimeService.startProcessInstanceById(definition.getId(), businessKey, variables);
        // 设置流程名字
        runtimeService.setProcessInstanceName(instance.getId(), definition.getName());
//        Authentication.setAuthenticatedUserId(null);
        // 补全流程实例的拓展表
        processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId())
                .setFormVariables(variables).setFormRecordId(formRecordId).setFormStatus(formStatus));
        // 如果用户为实例发起人，自动完成任务
        this.autoCommitSubmitterTask(userId, instance.getId());
        return instance.getId();
    }

    /**
     *  自动提交完成提交人的任务
     * @param userId
     * @param processInstanceId
     */
    private void autoCommitSubmitterTask(Long userId, String processInstanceId) {
        List<Task> tasks = taskService.getTasksByProcessInstanceIds(Lists.newArrayList(processInstanceId));
        for (Task task : tasks) {
            // 约定：发起者节点为 initiator ,则自动完成任务
            String taskDefinitionKey = task.getTaskDefinitionKey();
            String processDefinitionId = task.getProcessDefinitionId();
            //设置的是脚本方式 @BpmTaskAssignRuleTypeEnum.SCRIPT 而且options包含10，审批自动通过
            /**
             * 1. assign 默认为1，需要修改为提交人;
             * 2. 判断taskAssignRuleList中的情况，计算出实际的任务责任人; 然后把当前任务修改为计算出来的任务责任人
             */
//            BpmProcessInstanceExtDO bpmProcessInstanceExtDO = processInstanceExtMapper.selectByProcessInstanceId(processInstanceId);
//            Map<String, Object> formVariables = bpmProcessInstanceExtDO.getFormVariables();
//            formVariables.put("processInstanceId", processInstanceId);
            List<BpmTaskAssignRuleDO> taskAssignRuleList = taskAssignRuleService.getTaskAssignRuleListByProcessDefinitionId(processDefinitionId, taskDefinitionKey);

            List<BpmTaskAssignRuleDO> assignList = taskAssignRuleList.stream()
                    .filter(item -> Objects.equals(item.getType(), BpmTaskAssignRuleTypeEnum.SCRIPT.getType()))
                    .filter(item->item.getOptions().contains(10L))
                    .collect(Collectors.toList());
//            List<BpmTaskAssignRuleDO> variablesAssignList = taskAssignRuleList.stream()
//                    .filter(item -> Objects.equals(item.getType(), BpmTaskAssignRuleTypeEnum.VARIABLES.getType()))
//                    .collect(Collectors.toList());
//            Set<Long> assigns = new HashSet<>();
//            taskAssignRuleList.stream().map(item -> taskAssignRuleService.calculateTaskCandidateUsers(formVariables, item)).forEach(item -> assigns.addAll(item));
            if (!CollectionUtils.isEmpty(assignList)
//                    || (assigns.contains(userId) && !CollectionUtils.isEmpty(variablesAssignList))
                    || FlowableConstant.FLOW_SUBMITTER_VAR.equals(task.getTaskDefinitionKey())) {
                BpmTaskApproveReqVO approveVO = new BpmTaskApproveReqVO();
                approveVO.setId(task.getId());
                taskService.autoApproveTask(userId,approveVO);
                autoCommitSubmitterTask(userId,processInstanceId);
                log.info("此流程实例:{},第一个任务节点为流程发起人节点，设置为自动审批通过",processInstanceId);
            }else{
                String processDefinitionBpmnXML = bpmDefinitionService.getProcessDefinitionBpmnXML(task.getProcessDefinitionId());
                Map<String, Object> buttonMap = null;
                String approveAutoAgree = BpmAutoAgreeEnum.NOT_AGREE.getType();
                if(StringUtils.isNoneBlank(processInstanceId)){
                    buttonMap = bpmDefinitionService.readxmlByDom(processDefinitionBpmnXML, processInstanceId);
                     approveAutoAgree = buttonMap.get("approveAutoAgree").toString();
                }
                if ( approveAutoAgree.equals(BpmAutoAgreeEnum.AGREE.getType())) {
                    BpmTaskApproveReqVO approveVO = new BpmTaskApproveReqVO();
                    try {
                        approveVO.setId(task.getId());
                        taskService.autoApproveTask(userId,approveVO);
                        autoCommitSubmitterTask(userId,processInstanceId);
                        log.info("此流程实例:{},下一个为当前人节点，设置为自动审批通过",processInstanceId);
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    /**
     * 表单远端数据映射，实现存储值到显示的转换
     * @param formId
     * @param processInstanceExt
     */
    private void formDataMap(Long formId, BpmProcessInstanceExtDO processInstanceExt) {
        List<Map<String, Object>> dataMap = new ArrayList<>();
        dataMap.add(processInstanceExt.getFormVariables());
        CommonResult<List<Map<String, Object>>> formDataResult = currencyDataApi.selectDataByChange(formId, dataMap);
        List<Map<String, Object>> checkedData = formDataResult.getCheckedData();
        if (CollectionUtil.isNotEmpty(checkedData)) {
            processInstanceExt.setFormVariables(formDataResult.getCheckedData().get(0));
        }
    }
}
